package com.gitee.wsl.platform

//enum class PlatformType {
//    UNKNOWN,
//    ANDROID,
//    ANDROID_NATIVE,
//    JVM,
//    LINUX,
//    JS,
//    IOS,
//    MAC,
//    WINDOWS,
//    NATIVE,
//    WASM_JS
//}

fun Platform.isAndroid(): Boolean =  this.current.isAndroid
fun Platform.isAppleMacOs(): Boolean =  this.current.isMacDesktop
fun Platform.isApple(): Boolean = this.current.isMac
fun Platform.isWindows(): Boolean = this.current.isMacDesktop
fun Platform.isLinux(): Boolean = this.current.isLinuxDesktop
fun Platform.isJvmOrAndroid(): Boolean =  this.current.isJvmOrAndroid
fun Platform.isJvm(): Boolean = this.current.isJvm
fun Platform.isJsOrWasm(): Boolean = this.current.isJs
fun Platform.isWasmJs(): Boolean = this.current.isNodejs
fun Platform.isBrowser(): Boolean {
   return if(isJsOrWasm()){
       this as JSPlatform
       this.jsRuntime == JsRuntime.Browser
   } else false
}

fun Platform.isNodejs(): Boolean {
   return if(isJsOrWasm()){
       this as JSPlatform
       this.jsRuntime == JsRuntime.Node
   } else false
}

fun Platform.isDesktop():Boolean = current.isDesktop

fun Platform.isMobile():Boolean = this.current.isMobile


sealed class PlatformType {
    /**
     * Running on JS vm environment
     */
    sealed class JS : PlatformType() {
        data class Node(val os: OS, val nodeVersion: String, val v8Version: String) : JS()

        data class Browser(val userAgent: String) : JS()

    }

    data class Wasm(val arch: Arch,val version: String = "") : PlatformType()

    sealed class OS( open val arch: Arch) : PlatformType() {

        data class Unknown(override val arch: Arch = Arch.UNKNOWN , val version: String = "") : OS(arch)

        data class IOS(override val arch: Arch, val version: String, val isSimulator: Boolean=false) : OS(arch)

        data class WatchOs(override val arch: Arch, val version: String, val isSimulator: Boolean=false) : OS(arch)

        data class TvOs(override val arch: Arch, val version: String, val isSimulator: Boolean=false) : OS(arch)

        data class HarmonyOS(override val arch: Arch, val version: String, val isSimulator: Boolean=false) : OS(arch)

        data class Android(
            override val arch: Arch,
            val buildNumber: Int=-1,
            val androidVersion: String="",
            val isWatch: Boolean=false,
            val isTv: Boolean=false,
        ) : OS(arch)

         sealed class Desktop(override val arch: Arch,  open val version: String,  open val isJvm: Boolean = false) : OS(arch) {
             data class Linux(override val arch: Arch, override val version: String, override val isJvm: Boolean = false) : Desktop(arch,version,isJvm)
             data class Windows(override val arch: Arch, override val version: String, override val isJvm: Boolean = false) : Desktop(arch,version,isJvm)
             data class MacOs(override val arch: Arch, override val version: String, override val isJvm: Boolean = false) : Desktop(arch,version,isJvm)
        }
    }
}

val PlatformType.isJs  get() = this is PlatformType.JS
val PlatformType.isNodejs  get() = this is PlatformType.JS.Node
val PlatformType.isNodejsOnMac  get() = this is PlatformType.JS.Node && this.os.isMacDesktop
val PlatformType.isNodejsOnLinux  get() = this is PlatformType.JS.Node && this.os.isLinuxDesktop
val PlatformType.isNodejsOnWindows  get() = this is PlatformType.JS.Node && this.os.isWindowsDesktop

val PlatformType.isBrowser  get() = this is PlatformType.JS.Browser

val PlatformType.isMacIos  get() = this is PlatformType.OS.IOS
val PlatformType.isMacTvOs  get() = this is PlatformType.OS.TvOs
val PlatformType.isMacWatchOs  get() = this is PlatformType.OS.WatchOs
val PlatformType.isMacDesktop  get() = this is PlatformType.OS.Desktop.MacOs
val PlatformType.isMac  get() = isMacDesktop || isMacIos || isMacTvOs || isMacWatchOs || isNodejsOnMac

val PlatformType.isAndroid  get() = this is PlatformType.OS.Android
val PlatformType.isDesktop  get() = this is PlatformType.OS.Desktop

val PlatformType.isHarmonyOS get() = this is PlatformType.OS.HarmonyOS
val PlatformType.isMobile  get() = isAndroid || isMacIos || isHarmonyOS//|| isMacTvOs || isMacWatchOs

val PlatformType.isLinuxDesktop  get() = this is PlatformType.OS.Desktop.Linux
val PlatformType.isLinux  get() = isLinuxDesktop || isNodejsOnLinux
val PlatformType.isWindowsDesktop  get() = this is PlatformType.OS.Desktop.Windows
val PlatformType.isWindows  get() = isWindowsDesktop || isNodejsOnWindows

val PlatformType.isJvm  get() = this is PlatformType.OS.Desktop && this.isJvm

val PlatformType.isJvmOrAndroid get() = isJvm || isAndroid

val PlatformType.isNative  get() = isDesktop && !isJvm


sealed class Arch(val name: String) {
    data object UNKNOWN : Arch("unknown")
    data object X64 : Arch("x64")
    data object Arm64 : Arch("arm64")

    data object Arm32 : Arch("arm32")
    data object X32 : Arch("x32")

    data object MIPS32: Arch("mip32")
    data object MIPSEL32: Arch("mipsel32")
    data object WASM32: Arch("wasm32")

    override fun toString(): String {
        return name
    }

    companion object {
        private val DefinedArchStrings = mapOf(
            X64 to listOf(
                "amd64", "x64"
            ),
            Arm64 to listOf(
                "arm64", "aarch64"
            ),
            Arm32 to listOf(
                "arm32", "aarch32"
            ),
            X32 to listOf(
                "x86",
            ),
        )

        fun fromString(archName: String): Arch {
            val a = archName.lowercase()
            return DefinedArchStrings.entries.firstOrNull {
                a in it.value
            }?.key?:  UNKNOWN
        }


        private fun normalize(value: String): String {
            return value.lowercase().replace("[^a-z0-9]+".toRegex(), "")
        }

        private fun normalizeArch(value: String): String {
            var value = value
            value = normalize(value)
            if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$".toRegex())) {
                return "x86_64"
            }
            if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$".toRegex())) {
                return "x86_32"
            }
            if (value.matches("^(ia64|itanium64)$".toRegex())) {
                return "itanium_64"
            }
            if (value.matches("^(sparc|sparc32)$".toRegex())) {
                return "sparc_32"
            }
            if (value.matches("^(sparcv9|sparc64)$".toRegex())) {
                return "sparc_64"
            }
            if (value.matches("^(arm|arm32)$".toRegex())) {
                return "arm_32"
            }
            if ("aarch64" == value) {
                return "aarch_64"
            }
            if (value.matches("^(ppc|ppc32)$".toRegex())) {
                return "ppc_32"
            }
            if ("ppc64" == value) {
                return "ppc_64"
            }
            if ("ppc64le" == value) {
                return "ppcle_64"
            }
            if ("s390" == value) {
                return "s390_32"
            }
            if ("s390x" == value) {
                return "s390_64"
            }

            return "unknown"
        }

        private fun normalizeOs(value: String): String {
            var value = value
            value = normalize(value)
            if (value.startsWith("aix")) {
                return "aix"
            }
            if (value.startsWith("hpux")) {
                return "hpux"
            }
            if (value.startsWith("os400")) {
                // Avoid the names such as os4000
                if (value.length <= 5 || !value[5].isDigit()) {
                    return "os400"
                }
            }
            if (value.startsWith("linux")) {
                return "linux"
            }
            if (value.startsWith("macosx") || value.startsWith("osx")) {
                return "osx"
            }
            if (value.startsWith("freebsd")) {
                return "freebsd"
            }
            if (value.startsWith("openbsd")) {
                return "openbsd"
            }
            if (value.startsWith("netbsd")) {
                return "netbsd"
            }
            if (value.startsWith("solaris") || value.startsWith("sunos")) {
                return "sunos"
            }
            if (value.startsWith("windows")) {
                return "windows"
            }

            return "unknown"
        }
    }
}

interface ArchFinder {
    fun getCurrentArch(): Arch
}
